﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Deployment.Application;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Microsoft.Win32;

namespace VSCPPublishPluginSetupApplication
{
	public partial class Form1 : Form
	{
		public Form1()
		{
			InitializeComponent();
		}

		private void btnExit_Click(object sender, EventArgs e)
		{
			this.Close();
			Application.Exit();
		}

		private void Form1_Load(object sender, EventArgs e)
		{
			ReadVsInstallState();
			ReadVersionInfo();
		}

		private void ReadVersionInfo()
		{
			var appVer = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version;
			statusAssemblyVersion.Text = appVer.ToString();

			if (ApplicationDeployment.IsNetworkDeployed)
			{
				Version clickOnceVer = ApplicationDeployment.CurrentDeployment.CurrentVersion;
				statusClickOnceVersion.Text = clickOnceVer.ToString();
			}
			else
			{
				statusClickOnceVersion.Text = "Not deployed";
			}



			var availableVersion = GetAvailableVersion();
			txtAvailableVersion.Text = availableVersion.ToString();


			var curVer = GetCurrentVersion();
			if (0 == curVer.CompareTo(new Version()))
			{
				// not installed
				btnInstall.Text = "Install";
				txtCurrentVersion.Text = "Not Installed";
			}
			else
			{
				txtCurrentVersion.Text = curVer.ToString();

				switch (curVer.CompareTo(availableVersion))
				{
					case -1:
						btnInstall.Text = "Update";
						break;
					case 0:
						btnInstall.Text = "Reinstall";
						break;
					case 1:
						btnInstall.Text = "Install";
						break;
				}
			}
		}

		private string _vsInstallDir = null;
		private string _devenvDir = null;
		private void ReadVsInstallState()
		{
			// logic taken from vcvarsall.bat && vsvars32.bat && VCVarsQueryRegistry.bat


			_vsInstallDir = GetVsInstallDir("10.0");
			if (null == _vsInstallDir)
			{
				btnInstall.Enabled = false;
				lblVs10NotFound.Visible = true;
			}
			else
			{
				_devenvDir = Path.Combine(_vsInstallDir, "Common7\\IDE\\");
			}
		}

		private Version GetAvailableVersion()
		{
			var fileData = File.ReadAllText(Directory.GetCurrentDirectory() + "\\plugin\\extension.vsixmanifest");
			const string versionStartString = "<Version>";
			const string versionEndString = "</Version>";
			var iStart = fileData.IndexOf(versionStartString);
			var iEnd = fileData.IndexOf(versionEndString);
			if (iStart < 0 || iEnd < 0)
			{
				// could not read version
				return new Version();
			}

			iStart += versionStartString.Length;
			var s = fileData.Substring(iStart, iEnd - iStart);
			return Version.Parse(s);
		}
		private Version GetCurrentVersion(string hive = "")
		{
			var key = Registry.CurrentUser.OpenSubKey("Software\\Microsoft\\VisualStudio\\10.0" + (hive ?? "") + "_Config\\Packages\\{32313a05-2e98-420f-adda-5d780102bd18}");
			if (null == key)
				return new Version();
			var val = key.GetValue("CodeBase") as string;
			if (string.IsNullOrEmpty(val))
				return new Version();
			var parts = val.Split('\\');
			if (parts.Length < 2)
				return new Version();

			var verString = parts[parts.Length - 2];
			return Version.Parse(verString);
		}

		private void btnInstall_Click(object sender, EventArgs e)
		{
			btnInstall.Enabled = btnExit.Enabled = false;
			pbWorking.Visible = true;
			UninstallExtension();
		}

		private void ForceVsToSeeExtension()
		{
			var proc = new Process
					   {
						   StartInfo =
							   {
								   FileName = Path.Combine(_devenvDir, "devenv.exe"),
								   Arguments = "/setup",
								   Verb = "runas"
							   }
					   };
			proc.EnableRaisingEvents = true;
			try
			{
				proc.Exited += (s, e) => PostInstall();
				proc.Start();
			}
			catch (Exception)
			{
				PostInstall();
			}
		}


		private void PostInstall()
		{
			if (this.InvokeRequired)
			{
				this.Invoke(new MethodInvoker(() => PostInstall()));
				return;
			}
			ReadVersionInfo();
			pbWorking.Visible = false;
			btnInstall.Enabled = btnExit.Enabled = true;
		}


		#region Get VS InstallDir

		private string GetVsInstallDir(string vsVer)
		{
			string loc;
			loc = GetVSInstallDirHelper32(Registry.LocalMachine, vsVer);
			if (!string.IsNullOrEmpty(loc))
				return loc;
			loc = GetVSInstallDirHelper32(Registry.CurrentUser, vsVer);
			if (!string.IsNullOrEmpty(loc))
				return loc;
			loc = GetVSInstallDirHelper64(Registry.LocalMachine, vsVer);
			if (!string.IsNullOrEmpty(loc))
				return loc;
			loc = GetVSInstallDirHelper64(Registry.CurrentUser, vsVer);
			if (!string.IsNullOrEmpty(loc))
				return loc;
			return null;
		}
		private string GetVSInstallDirHelper32(RegistryKey registryHive, string vsVer)
		{
			var key = registryHive.OpenSubKey("SOFTWARE\\Microsoft\\VisualStudio\\SxS\\VS7");
			return GetVSInstallDirHelper_Common(key, vsVer);
		}
		private string GetVSInstallDirHelper64(RegistryKey registryHive, string vsVer)
		{
			var key = registryHive.OpenSubKey("SOFTWARE\\Wow6432Node\\Microsoft\\VisualStudio\\SxS\\VS7");
			return GetVSInstallDirHelper_Common(key, vsVer);
		}
		private string GetVSInstallDirHelper_Common(RegistryKey key, string vsVer)
		{
			if (null == key)
				return null;
			var val = key.GetValue(vsVer) as string;
			return val;
		}

		#endregion


		private void InstallExtension()
		{
			var proc = new Process
					   {
						   StartInfo =
							   {
								   FileName = Path.Combine(_devenvDir, "VSIXInstaller.exe"),
								   Arguments = "\"" + Directory.GetCurrentDirectory() + "\\plugin\\VSCPPublishPlugin.vsix" + "\""
							   }
					   };
			proc.EnableRaisingEvents = true;
			try
			{
				proc.Exited += (s, e) => ForceVsToSeeExtension();
				proc.Start();
			}
			catch (Exception)
			{
				PostInstall();
			}
		}

		private void UninstallExtension()
		{
			const string vsixID = "VSCPPublishPlugin.DoubleASoftware.32313a05-2e98-420f-adda-5d780102bd18";
			var proc = new Process
					   {
						   StartInfo =
							   {
								   FileName = Path.Combine(_devenvDir, "VSIXInstaller.exe"),
								   Arguments = "/q /uninstall:" + vsixID
							   }
					   };
			proc.EnableRaisingEvents = true;
			try
			{
				proc.Exited += (s, e) => InstallExtension();
				proc.Start();
			}
			catch (Exception)
			{
				PostInstall();
			}
		}
	}
}
